package org.wheel.plugins.toolkit.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;


/**
 * 反射工具类
 * @author Alan
 *
 */
public class ReflectUtil extends cn.hutool.core.util.ReflectUtil {

	// 直接使用 LogFactory 创建日志对象，Hutool 会自动检测项目中的日志框架（优先级：Slf4j > Log4j > Logback > JDK Logging）
	private static final Log logger = LogFactory.get();

	private static final String SETTER_PREFIX = "set";

	private static final String GETTER_PREFIX = "get";

	private static final String CGLIB_CLASS_SEPARATOR = "$$";
	
	/**
	 * This attribute of the object is assigned based on the name and value of the attribute passed in.
	 * 根据传入的属性名称和属性值，对该对象的这个属性进行赋值
	 * @param obj 对象
	 * @param attributeName 属性名称
	 * @param attributeValue 属性值
	 * @throws Exception
	 * @author liukang
	 */
	public static void perInserOrUpdate (Object obj,String attributeName, Object attributeValue) throws Exception {
		Field field = ReflectUtil.getField(obj.getClass(), attributeName);
		if(field != null) {
//		    PropertyDescriptor pd = org.springframework.beans.BeanUtils.getPropertyDescriptor(obj.getClass(), attributeName);
			PropertyDescriptor pd = BeanUtil.getPropertyDescriptor(obj.getClass(), attributeName);
		    if(attributeValue instanceof LocalDateTime) {
	            if(Date.class.isAssignableFrom(pd.getPropertyType())) {
	                attributeValue = Date.from( ((LocalDateTime)attributeValue)
	                    .atZone( ZoneId.systemDefault()).toInstant());
	            }
		    }else if(attributeValue instanceof Date){
		        if(LocalDateTime.class.isAssignableFrom(pd.getPropertyType())) {
		            attributeValue = ((Date)attributeValue).toInstant()
		                .atZone( ZoneId.systemDefault() ).toLocalDateTime();
		        }
		    }
			Method m = ReflectUtil.getMethod(obj.getClass(), "set"+ StrUtil.upperFirst(attributeName),field.getType() );
			if(validateDataType(field, attributeValue)) {
				m.invoke(obj, attributeValue);
			}
		}
	}
	
	/**
	 * Determine if the data type matches the value type
	 * 判断数据类型与传值类型是否匹配
	 * @param field 类中的属性对象
	 * @param attributeValue 要设置的属性值
	 * @return true-匹配 / false-不匹配
	 * @author Alan
	 */
	public static boolean validateDataType(Field field, Object attributeValue) {
		Class<?> typeClazz = field.getType();
		boolean validate = false;
		if(attributeValue instanceof String && typeClazz.getName().equals(String.class.getName())) {
			validate = true;
		}else if(attributeValue instanceof Date && typeClazz.getName().equals(Date.class.getName())) {
			validate = true;
		}else if(attributeValue instanceof LocalDateTime && typeClazz.getName().equals(LocalDateTime.class.getName())) {
			validate = true;
		}else if(attributeValue instanceof LocalDate && typeClazz.getName().equals(LocalDate.class.getName())) {
			validate = true;
		}else if(attributeValue instanceof LocalTime && typeClazz.getName().equals(LocalTime.class.getName())) {
			validate = true;
		}else if(attributeValue instanceof Integer 
				&& (typeClazz.getName().equals(Integer.class.getName()) || typeClazz.getName().equals(int.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Long 
				&& (typeClazz.getName().equals(Long.class.getName()) || typeClazz.getName().equals(long.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Float 
				&& (typeClazz.getName().equals(Float.class.getName()) || typeClazz.getName().equals(float.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Double 
				&& (typeClazz.getName().equals(Double.class.getName()) || typeClazz.getName().equals(double.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Byte 
				&& (typeClazz.getName().equals(Byte.class.getName()) || typeClazz.getName().equals(byte.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Short 
				&& (typeClazz.getName().equals(Short.class.getName()) || typeClazz.getName().equals(short.class.getName()))) {
			validate = true;
		}else if(attributeValue instanceof Number && typeClazz.getName().equals(Number.class.getName())) {
			validate = true;
		}
		return validate;
	}
	
	/**
	 * Determine whether the property of the object has a value or not
	 * 判断数据对象的属性值是否存在，如果不为空，则返回true。否则返回false
	 * @param obj 对象
	 * @param attributeName 属性名称
	 * @return boolean
	 * @throws Exception
	 * @author liukang
	 */
	public  static boolean judgmentValue(Object obj,String attributeName) throws Exception{
		Field field = ReflectUtil.getField(obj.getClass(), attributeName);
		if(field != null) {
			Method m = ReflectUtil.getMethod(obj.getClass(), "get"+StrUtil.upperFirst(attributeName));
			if(m != null && ObjectUtil.isNotEmpty(m.invoke(obj)) /*&& m.invoke(obj)!=null && m.invoke(obj) !=""*/ ) {
				return true;
			}else {
				return false;
			}
		}else {
			return false;
		}
	}
	
	/**
	 * Assign the attribute value of the object source to the attribute field of the to object with the same name and type
	 * 把对象source的属性值赋给to对象的属性名称相同且类型相同的属性字段
	 * @param source 源实体对象
	 * @param to 目标实体对象
	 * @throws Exception
	 * @author liukang
	 */
	public static void copyObj(Object source, Object to) throws Exception {
		Field[] toField = ReflectUtil.getFields(to.getClass());
		for (int i = 0; i < toField.length; i++) {
			String toFieldName = toField[i].getName();
			if (!"serialVersionUID".equals(toFieldName)) {
				Field field = ReflectUtil.getField(source.getClass(), toFieldName);
				if (null != field && toField[i].getType().getName().equals(field.getType().getName())) {
					Method sourceMethod = ReflectUtil.getMethod(source.getClass(), "get" + StrUtil.upperFirst(toFieldName));
					Method toMethod = ReflectUtil.getMethod(to.getClass(), "set" + StrUtil.upperFirst(toFieldName), field.getType());
					if (null != sourceMethod && null != toMethod) {
						if (sourceMethod.invoke(source) != null) {
							toMethod.invoke(to, sourceMethod.invoke(source));
						}
					}
				}
			}
		}
	}
	
	/**
	 * 不同时区间的日期转换(未解决夏令时)
	 * @param sourceDate 源时间
	 * @param sourceTimeZone 源时区代码
	 * @param targetTimeZone 目标时区代码
	 * @return
	 */
	public static Date dateTransformBetweenTimeZone(Date sourceDate, String  sourceTimeZone, String targetTimeZone) {
		TimeZone sourceZone = TimeZone.getTimeZone(sourceTimeZone);
		TimeZone toZone = TimeZone.getTimeZone(targetTimeZone);
		Long targetTime = sourceDate.getTime() - sourceZone.getRawOffset() + toZone.getRawOffset();
		return new Date(targetTime);
	}    
		
	/**
	 * 不同时区间的日期转换(解决美国夏令时问题)
	 * @param sourceDate 源时间
	 * @param sourceTimeZone 源时区代码
	 * @param targetTimeZone 目标时区代码
	 * @return
	 * @author liukang
	 */
	public static Date getZongTime(Date sourceDate, String sourceTimeZone, String targetTimeZone) {
		ZoneId src = ZoneId.of(sourceTimeZone);
		Instant instant = sourceDate.toInstant();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, src);
//		LocalDate localDate = localDateTime.toLocalDate();
		ZonedDateTime srcTime = localDateTime.atZone(src);
		ZoneId dest = ZoneId.of(targetTimeZone);
		ZonedDateTime destTime = srcTime.withZoneSameInstant(dest);
		// 处理重叠问题
		long hours = Duration.between(destTime.withEarlierOffsetAtOverlap(), destTime.withLaterOffsetAtOverlap()).toHours();
		destTime = destTime.plusHours(hours);
		Instant instants = localDateTime.atZone(dest).toInstant();
		
   
		return Date.from(instants); 
	} 
	
	/**
	 * 日期格式化，将日期范围格式化(例子：7-7 August 2019)
	 * @param deliveryStartTime 开始日期
	 * @param deliveryEndTime 结束日期
	 * @return String
	 * @author liukang
	 */
	public static String getEnglishDate(Date deliveryStartTime, Date deliveryEndTime) {
		SimpleDateFormat sdfM = new SimpleDateFormat("MMM", Locale.UK);
		SimpleDateFormat sdfY = new SimpleDateFormat("yyyy", Locale.UK);
		String dateStartM=sdfM.format(deliveryStartTime);
		String dateStartY=sdfY.format(deliveryStartTime);
		String dateEndM=sdfM.format(deliveryEndTime);
		String dateEndY=sdfY.format(deliveryEndTime);
		Calendar cal = Calendar.getInstance();
		cal.setTime(deliveryStartTime);
		int dayStr =  cal.get(Calendar.DAY_OF_MONTH);  //获取月的第几日
		cal.setTime(deliveryEndTime);
		int dayEnd =  cal.get(Calendar.DAY_OF_MONTH);  //获取月的第几日
		String dateString="";
//		如果年份和月份相同
		if(dateStartM.equals(dateEndM)&&dateStartY.equals(dateEndY)){
			dateString = dayStr+"-"+dayEnd+" "+dateStartM.toUpperCase()+" "+dateStartY.toUpperCase();
//		如果年份相同但月份不同	
		}else if(!dateStartM.equals(dateEndM)&&dateStartY.equals(dateEndY)){
			dateString = dayStr+" "+dateStartM.toUpperCase()+"-"+dayEnd+" "+dateEndM.toUpperCase()+" "+dateStartY.toUpperCase();
//		如果年份不同
		}else if(!dateStartY.equals(dateEndY)){
			dateString = dayStr+" "+dateStartM.toUpperCase()+" "+dateStartY.toUpperCase()+"-"+dayEnd+" "+dateEndM.toUpperCase()+" "+dateEndY.toUpperCase();
		}
		
		return dateString;
	}
	
	/**
	 * 将邮件窗口开发日期范围分解并格式化
	 * @param date 邮件窗口打开日期范围
	 * @param type 1开始日期 2关闭日期
	 * @return String 日期格式化 yyyy-MM-dd
	 * @author dell
	 * @throws ParseException 
	 */
	
    public static Date dateString(String date,String type) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		StringBuilder result = new StringBuilder();
//		Calendar cal = Calendar.getInstance();
		//分解邮件开启窗口日期范围
        String[] str=date.split(" ");
		
        
        String year="";
        String month = "";
        String monthStr="";
        String dayStart="";
        String dayEnd ="";
//      如果是不同月或不同年的情况
       if(str.length>3){
    	   String[] str1=date.split("-");
    	   
    	   String[] str11=str1[0].split(" ");
    	   String[] str12=str1[1].split(" ");
       	if(type.equals("1")){
       		
       		
//       		如果是不同年的情况
       		if(str11.length>2){
       			monthStr=str11[1];
       			dayStart=str11[0];
       			year=str11[2];
       		}else{
//       			如果是不同月的情况
       			monthStr=str11[1];
       			dayStart=str11[0];
       			year=str12[2];
       		}
       	}else{
       		monthStr=str12[1];
       		dayEnd=str12[0];
       		year=str12[2];
       	}
       }else{
    	   
    	   
    	 //当前年份
            year = str[2];
           
           
           //分解得到英文月份
            monthStr = str[1];
           //分解获取到日期范围 列如1-20号
           String dayStr = str[0];
           //分解开始日期和关闭日期
           String[] dayS=dayStr.split("-");
           //分别将开始日期和关闭日期赋值
            dayStart = dayS[0];
            dayEnd = dayS[1];
       }
        

        switch (monthStr.toUpperCase()) {
        //根据分解的英文月份，转换成数字月份
        case "JAN":
            month = "1";
            break;
        case "FEB":
            month = "2";
            break;
        case "MAR":
            month = "3";
            break;
        case "APR":
            month = "4";
            break;
        case "MAY":
            month = "5";
            break;
        case "JUN":
            month = "6";
            break;
        case "JUL":
            month = "7";
            break;
        case "AUG":
            month = "8";
            break;
        case "SEP":
            month = "9";
            break;
        case "OCT":
            month = "10";
            break;
        case "NOV":
            month = "11";
            break;
        case "DEC":
            month = "12";
            break;
        }
        if(type.equals("1")) {
        	result.append(year).append("-").append(month).append("-").append(dayStart);
        }else {
        	result.append(year).append("-").append(month).append("-").append(dayEnd);
        }
        return sdf.parse(result.toString());
	}
	
	/**
	 * 根据日期是每周的第几天来获取相应的英文单词（1标识周日，2标识周一。。。6表示周日）
	 * @param week
	 * @return String
	 * @author liukang
	 */
	public static String getWeekEn(String week) {
//		Map<String, String> map = Maps.newHashMap();
		Map<String, String> map = new HashMap<>();
		map.put("2", "Monday");
		map.put("3", "Tuesday");
		map.put("4", "Wednesday");
		map.put("5", "Thursday");
		map.put("6", "Friday");
		map.put("7", "Saturday");
		map.put("1", "Sunday");
		return map.get(week);
	}
	
	public static void main (String [] args) throws ParseException {
//		Calendar sss=Calendar.getInstance();
		String password=getRandomPassword();
		System.out.println(password);
	}
	/**
	 * 随机生成一个六位数的纯数字的密码
	 * @return
	 */
	public static String getRandomPassword() {
		Random ran = new Random();
		StringBuffer password=new StringBuffer();
		for(int i=0;i<=5;i++) {
			int ran1 = ran.nextInt(10);
			password.append(String.valueOf(ran1));
		 }
		return password.toString();
	}
	
	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
	 * 如无法找到, 返回Object.class.
	 * 
	 * 如public UserDao extends HibernateDao<User,Long>
	 *
	 * @param clazz clazz The class to introspect
	 * @param index the Index of the generic ddeclaration,start from 0.
	 * @return the index generic declaration, or Object.class if cannot be determined
	 */
	public static Class<?> getClassSuperGenricType(final Class<?> clazz, final int index) {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
					+ params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}

		return (Class<?>) params[index];
	}
	/**
	 * 调用Getter方法.
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static Object invokeGetter(Object obj, String propertyName) {
		Object object = obj;
		for (String name : StrUtil.split(propertyName, ".")){
			String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(name);
			object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
		}
		return object;
	}

	/**
	 * 调用Setter方法, 仅匹配方法名。
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static void invokeSetter(Object obj, String propertyName, Object value) {
		Object object = obj;
		List<String> names = StrUtil.split(propertyName, ".");
		for (int i=0; i<names.size(); i++){
			if(i<names.size()-1){
				String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(names.get(i));
				object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
			}else{
				String setterMethodName = SETTER_PREFIX + StrUtil.upperFirst(names.get(i));
				invokeMethodByName(object, setterMethodName, new Object[] { value });
			}
		}
	}

	/**
	 * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
	 */
	public static Object getFieldValue(final Object obj, final String fieldName) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
		}

		Object result = null;
		try {
			result = field.get(obj);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常{}", e.getMessage());
		}
		return result;
	}

	/**
	 * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
	 */
	public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
		}

		try {
			field.set(obj, value);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	/**
	 * 直接调用对象方法, 无视private/protected修饰符.
	 * 用于一次性调用的情况，否则应使用getAccessibleMethod()函数获得Method后反复调用.
	 * 同时匹配方法名+参数类型，
	 */
	public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
			final Object[] args) {
		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
		if (method == null) {
			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
		}

		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	/**
	 * 直接调用对象方法, 无视private/protected修饰符，
	 * 用于一次性调用的情况，否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
	 * 只匹配函数名，如果有多个同名函数调用第一个。
	 */
	public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
		Method method = getAccessibleMethodByName(obj, methodName);
		if (method == null) {
			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
		}

		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
	 * 
	 * 如向上转型到Object仍无法找到, 返回null.
	 */
	public static Field getAccessibleField(final Object obj, final String fieldName) {
		Assert.notNull(obj, "object can't be null");
		Assert.notBlank(fieldName, "fieldName can't be blank");
		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				Field field = superClass.getDeclaredField(fieldName);
				makeAccessible(field);
				return field;
			} catch (NoSuchFieldException e) {//NOSONAR
				// Field不在当前类定义,继续向上转型
				continue;// new add
			}
		}
		return null;
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
	 * 如向上转型到Object仍无法找到, 返回null.
	 * 匹配函数名+参数类型。
	 * 
	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
	 */
	public static Method getAccessibleMethod(final Object obj, final String methodName,
			final Class<?>... parameterTypes) {
		Assert.notNull(obj, "object can't be null");
		Assert.notBlank(methodName, "methodName can't be blank");

		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
			try {
				Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
				makeAccessible(method);
				return method;
			} catch (NoSuchMethodException e) {
				// Method不在当前类定义,继续向上转型
				continue;// new add
			}
		}
		return null;
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
	 * 如向上转型到Object仍无法找到, 返回null.
	 * 只匹配函数名。
	 * 
	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
	 */
	public static Method getAccessibleMethodByName(final Object obj, final String methodName) {
		Assert.notNull(obj, "object can't be null");
		Assert.notBlank(methodName, "methodName can't be blank");

		for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
			Method[] methods = searchType.getDeclaredMethods();
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					makeAccessible(method);
					return method;
				}
			}
		}
		return null;
	}

	/**
	 * 改变private/protected的方法为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。
	 */
	public static void makeAccessible(Method method) {
		if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
				&& !method.isAccessible()) {
			method.setAccessible(true);
		}
	}

	/**
	 * 改变private/protected的成员变量为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。
	 */
	public static void makeAccessible(Field field) {
		if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
				.isFinal(field.getModifiers())) && !field.isAccessible()) {
			field.setAccessible(true);
		}
	}

	/**
	 * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
	 * 如无法找到, 返回Object.class.
	 * eg.
	 * public UserDao extends HibernateDao<User>
	 *
	 * @param clazz The class to introspect
	 * @return the first generic declaration, or Object.class if cannot be determined
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getClassGenricType(final Class<?> clazz) {
		return (Class<T>) getClassGenricType(clazz, 0);
	}

	/**
	 * 得到当前类的泛型参数类型
	 * @param clazz
	 * @return
	 */
	public static Type getCurrentClassGenricType(final Class<?> clazz) {
		Type superclass = clazz.getGenericSuperclass();
		if (superclass instanceof Class) {
			throw new RuntimeException("Missing type parameter.");
		}
		return ((ParameterizedType) superclass).getActualTypeArguments()[0];
	}

	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
	 * 如无法找到, 返回Object.class.
	 * 
	 * 如public UserDao extends HibernateDao<User,Long>
	 *
	 * @param clazz clazz The class to introspect
	 * @param index the Index of the generic ddeclaration,start from 0.
	 * @return the index generic declaration, or Object.class if cannot be determined
	 */
	public static Class<?> getClassGenricType(final Class<?> clazz, final int index) {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
					+ params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}

		return (Class<?>) params[index];
	}
	
	public static Class<?> getUserClass(Object instance) {
		Assert.notNull(instance, "Instance must not be null");
		Class<?> clazz = instance.getClass();
		if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
			Class<?> superClass = clazz.getSuperclass();
			if (superClass != null && !Object.class.equals(superClass)) {
				return superClass;
			}
		}
		return clazz;

	}
	
	/**
	 * 将反射时的checked exception转换为unchecked exception.
	 */
	public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
		if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
				|| e instanceof NoSuchMethodException) {
			return new IllegalArgumentException(e);
		} else if (e instanceof InvocationTargetException) {
			return new RuntimeException(((InvocationTargetException) e).getTargetException());
		} else if (e instanceof RuntimeException) {
			return (RuntimeException) e;
		}
		return new RuntimeException("Unexpected Checked Exception.", e);
	}
}
